package com.yeskery.nut.extend.mcp.server.method;

import com.yeskery.nut.bean.ApplicationContext;
import com.yeskery.nut.extend.mcp.annotation.McpToolProperty;
import com.yeskery.nut.extend.mcp.core.ExecuteExceptionHandler;
import com.yeskery.nut.extend.mcp.core.ExecuteExceptionResult;
import com.yeskery.nut.extend.mcp.core.JsonMessage;
import com.yeskery.nut.extend.mcp.core.JsonResponse;
import com.yeskery.nut.extend.mcp.core.schema.ContentSchema;
import com.yeskery.nut.extend.mcp.core.schema.ToolSchema;
import com.yeskery.nut.extend.mcp.server.McpExecuteMetadata;
import com.yeskery.nut.extend.mcp.server.McpServerCapability;
import com.yeskery.nut.extend.mcp.server.McpToolMetadata;
import com.yeskery.nut.util.BeanUtils;
import com.yeskery.nut.util.StringUtils;

import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 工具调用方法处理器
 * @author sprout
 * 2025-04-17 15:20
 */
public class ToolsCallMethodHandler extends BaseCallMethodHandler {
    /**
     * 构造工具调用方法处理器
     * @param applicationContext  应用上下文
     * @param mcpServerCapability 服务能力
     */
    public ToolsCallMethodHandler(ApplicationContext applicationContext, McpServerCapability mcpServerCapability) {
        super(applicationContext, mcpServerCapability);
    }

    @Override
    protected void handleErrorResponse(ExecuteExceptionResult executeExceptionResult, JsonResponse jsonResponse) {
        if (executeExceptionResult.getIsError()) {
            super.handleErrorResponse(executeExceptionResult, jsonResponse);
        } else {
            List<ContentSchema.Content> contents = executeExceptionResult.getContents();
            if (contents == null) {
                contents = new ArrayList<>(1);
            }
            if (contents.isEmpty()) {
                ContentSchema.TextContent content = new ContentSchema.TextContent();
                content.setText(executeExceptionResult.getMessage());
                contents.add(content);
            }
            ToolSchema.CallToolResult result = new ToolSchema.CallToolResult();
            result.setContent(contents);
            result.setIsError(true);
            jsonResponse.setResult(result);
        }
    }

    @Override
    protected Object getCallRequest(JsonMessage jsonMessage) {
        return getJsonRequestObject(jsonMessage, ToolSchema.CallToolRequest.class);
    }

    @Override
    protected Map<String, Object> getCallRequestArguments(Object request) {
        return ((ToolSchema.CallToolRequest) request).getArguments();
    }

    @Override
    protected McpExecuteMetadata getCallRequestMetadata(Object request) {
        return getMcpServerCapability().getToolMetadata(((ToolSchema.CallToolRequest) request).getName());
    }

    @Override
    protected String getParameterName(Parameter parameter) {
        McpToolProperty mcpToolProperty = parameter.getAnnotation(McpToolProperty.class);
        return getParameterName(parameter, mcpToolProperty);
    }

    @Override
    protected boolean isParameterRequired(Parameter parameter) {
        McpToolProperty mcpToolProperty = parameter.getAnnotation(McpToolProperty.class);
        return isParameterRequired(mcpToolProperty);
    }

    @Override
    protected void handleResponse(McpExecuteMetadata callRequestMetadata, Object callRequest, Type returnType, Object invokeResult, JsonResponse jsonResponse) {
        if (BeanUtils.getDependBeanType(returnType).equals(ToolSchema.CallToolResult.class)) {
            jsonResponse.setResult(invokeResult);
            return;
        }
        List<ContentSchema.Content> contents = getInvokeResultContent(returnType, invokeResult);
        ToolSchema.CallToolResult result = new ToolSchema.CallToolResult();
        result.setContent(contents);
        result.setIsError(false);
        jsonResponse.setResult(result);
    }

    @Override
    protected ExecuteExceptionHandler getExecuteExceptionHandler(McpExecuteMetadata callRequestMetadata, Object callRequest) {
        return ((McpToolMetadata) callRequestMetadata).getTool().getExceptionHandler();
    }

    @Override
    protected String getDefaultExceptionMessage(Exception e, McpExecuteMetadata callRequestMetadata, Object callRequest) {
        return "Tool [" + ((ToolSchema.CallToolRequest) callRequest).getName() + "] Invoke Fail.";
    }

    /**
     * 获取参数名称
     * @param parameter 参数
     * @param mcpToolProperty 注解
     * @return 参数名称
     */
    private String getParameterName(Parameter parameter, McpToolProperty mcpToolProperty) {
        String name = parameter.getName();
        if (mcpToolProperty != null && !StringUtils.isBlank(mcpToolProperty.value())) {
            name = mcpToolProperty.value();
        }
        return name;
    }

    /**
     * 判断参数是否必填
     * @param mcpToolProperty 注解
     * @return 是否必填
     */
    private boolean isParameterRequired(McpToolProperty mcpToolProperty) {
        boolean required = true;
        if (mcpToolProperty != null) {
            required = mcpToolProperty.required();
        }
        return required;
    }
}
